#include <initializer_list>
#include <iostream>

template <typename T>
class SingleLinkedList {
private:
    class Node {
    private:
        T data;
        Node *next = nullptr;
        Node(T _val) : data(_val), next(nullptr) {}

        friend class SingleLinkedList<T>;
    };

    Node* head = nullptr;
    int size = 0;
    Node* currentPos = nullptr;

    void _emptyList() {
        Node* p = head;
        while (p != nullptr) {
            Node* t = p;
            p = p->next;
            delete t;
        }
        head = nullptr;
        currentPos = nullptr;
        size = 0;
    }

    void _copy(const SingleLinkedList<T> &_l) {
        Node *p = _l.head;
        while (p != nullptr) {
            Node* newNode = new Node(p->data);
            if (head == nullptr) {
                head = newNode;
                currentPos = head;
            } else {
                currentPos->next = newNode;
                currentPos = newNode;
            }
            ++size;
            p = p->next;
        }
    }

public:
    T getCurrentVal() const {
        if (currentPos == nullptr) {
            throw std::runtime_error("Current position is not set or list is empty.");
        }
        return currentPos->data;
    }

    void setCurrentVal(const T &_val) {
        if (currentPos == nullptr) {
            throw std::runtime_error("Current position is not set or list is empty.");
        }
        currentPos->data = _val;
    }

    bool isEmpty() const {
        return head == nullptr;
    }

    int getSize() const {
        return size;
    }

    void emptyList() {
        _emptyList();
    }

    bool find(const T &_val) {
        Node *p = head;
        while (p != nullptr) {
            if (p->data == _val) {
                currentPos = p;
                return true;
            }
            p = p->next;
        }
        return false;
    }

    SingleLinkedList() = default;

    ~SingleLinkedList() {
        _emptyList();
    }

    SingleLinkedList(std::initializer_list<T> _l) {
        for (auto i = _l.begin(); i != _l.end(); ++i) {
            insert(*i);
        }
    }

    void printList() const {
        Node* p = head;
        while (p != nullptr) {
            std::cout << p->data << "\t";
            p = p->next;
        }
        std::cout << std::endl;
    }

    SingleLinkedList(const SingleLinkedList<T> &_l) {
        _copy(_l);
    }

    SingleLinkedList<T>& operator=(const SingleLinkedList<T> &_l) {
        if (this == &_l) {
            return *this;
        }
        _emptyList();
        _copy(_l);
        return *this;
    }

    void insert(T _val) {
        Node* newNode = new Node(_val);
        if (head == nullptr) {
            head = newNode;
            currentPos = head;
        } else {
            if (currentPos == nullptr) {
                currentPos = head;
            }
            newNode->next = currentPos->next;
            currentPos->next = newNode;
            currentPos = newNode;
        }
        ++size;
    }
    
    void remove() {
        if (currentPos == nullptr || head == nullptr) {
            return;
        }

        if (head == currentPos && currentPos->next == nullptr) {
        delete head;
            head = nullptr;
            currentPos = nullptr;
            size = 0;
        } else if (currentPos->next != nullptr) {
            Node* toDelete = currentPos;
            if (head == currentPos) {
                head = currentPos->next;
                currentPos = head;
            } else {
                Node* p = head;
                while (p->next != currentPos) {
                    p = p->next;
                }
                p->next = currentPos->next;
                currentPos = currentPos->next;
            }
            delete toDelete;
            size--;
        } else {
            return;
        }
    }
};

int main(){
    SingleLinkedList<int> a{1,2,3,4,5};
    int a_get = a.getCurrentVal();
    std::cout << a_get << std::endl;

    SingleLinkedList<char> b{'a','c','e'};
    b.printList();

    SingleLinkedList<char> e;
    std::cout << b.isEmpty() << " "
              << e.isEmpty() << std::endl;

    SingleLinkedList<double> c1;
    SingleLinkedList<double> c2{1.5,2.0,9.0,4.7};
    SingleLinkedList<double> c3;
    c3 = c2;
    c1.insert(3.0);
    c2.insert(8.8);
    bool f_c3 = c3.find(2.0);
    c3.insert(8.8);
    c1.printList();
    c2.printList();
    c3.printList();

    e.remove();
    c1.remove();
    bool f = c2.find(9.0);
    c2.remove();
    e.printList();
    c1.printList();
    c2.printList();

    return 0;
}